package com.huawei.ohos.myapplication;

// ohos相关接口包
import com.huawei.ohos.myapplication.utils.CommonData;
import com.huawei.ohos.myapplication.utils.SendData;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.IAbilityConnection;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.ToastDialog;
import ohos.bundle.AbilityInfo;
import ohos.bundle.ElementName;
import ohos.bundle.IBundleManager;
import ohos.data.distributed.common.KvManagerConfig;
import ohos.data.distributed.common.KvManagerFactory;
import ohos.data.distributed.common.KvStoreException;
import ohos.distributedschedule.interwork.DeviceInfo;
import ohos.distributedschedule.interwork.DeviceManager;
import ohos.event.commonevent.*;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.rpc.IRemoteBroker;
import ohos.rpc.IRemoteObject;
import ohos.rpc.RemoteObject;
import ohos.rpc.RemoteException;
import ohos.rpc.MessageParcel;
import ohos.rpc.MessageOption;
import ohos.utils.zson.ZSONObject;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

import static ohos.security.SystemPermission.DISTRIBUTED_DATASYNC;

public class ServiceAbility extends Ability {
    // 定义日志标签
    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0, "JKY");

    private MyRemote remote = new MyRemote();

    private MyRemoteProxy proxy;

    private boolean isLocal = true; //是否是本地端

    private String localDeviceId;  //当前设备的ID

    private String remoteDeviceId;  //调起此ability的设备ID

    private IAbilityConnection conn;  //ability连接的回调

    private boolean isConnected = false;  //是否与ability连接

    private boolean isMainStart = false;  //mainAbility是否已启动

    @Override
    public void onStart(Intent intent) {
        HiLog.info(LABEL, "PictureGameServiceAbility::onStart");
        super.onStart(intent);
        grantPermission();
        initService(intent);
    }

    void grantPermission() {
        if (verifySelfPermission(DISTRIBUTED_DATASYNC) != IBundleManager.PERMISSION_GRANTED) {
            if (canRequestPermission(DISTRIBUTED_DATASYNC)) {
                requestPermissionsFromUser(new String[] {DISTRIBUTED_DATASYNC}, 1);
            }
        }
    }

    //初始化一些本地数据
    private void initService(Intent intent) {
        HiLog.info(LABEL,"initService");
        localDeviceId = KvManagerFactory.getInstance().createKvManager(new KvManagerConfig(this)).getLocalDeviceInfo().getId();
        HiLog.info(LABEL,"当前设备ID：" + localDeviceId);
        HiLog.info(LABEL,"是否有intent" + (intent));
        HiLog.info(LABEL,"当前是否是本地：" + isLocal);
    }

    //当此设备时被调起的ability时，初始化其他设备的Ability
    private void initRemoteProxy(MessageParcel data) {
        if(!isLocal) {
            HiLog.info(LABEL,"不是本地，接收到的设备ID：" + remoteDeviceId);
            connectRemotePa(remoteDeviceId, MyRemoteProxy.REQUEST_SEND_DATA, data);
        }
    }

    private void connectRemotePa(String deviceId, int requestType, MessageParcel data) {
        if(!deviceId.isEmpty()) {
            HiLog.info(LABEL,"与设备进行连接，ID为：" + deviceId);
            HiLog.info(LABEL,"当前设备ID为：" + localDeviceId);
            Intent connectPaIntent = new Intent();
            Operation operation = new Intent.OperationBuilder().withDeviceId(deviceId)
                    .withBundleName(getBundleName())
                    .withAbilityName(CommonData.ABILITY_SREVICE)
                    .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
                    .build();
            connectPaIntent.setParam(CommonData.KEY_REMOTE_DEVICEID, localDeviceId);
            connectPaIntent.setParam(CommonData.KEY_IS_LOCAL, isLocal);
            connectPaIntent.setOperation(operation);

            conn = new IAbilityConnection() {
                @Override
                public void onAbilityConnectDone(ElementName elementName, IRemoteObject remote, int resultCode) {
                    HiLog.info(LABEL, "onAbilityConnectDone......");
                    connectAbility(elementName, remote, requestType, data);
                }

                @Override
                public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {
                    disconnectAbility(this);
                    HiLog.info(LABEL, "onAbilityDisconnectDone......");
                }
            };
            isConnected = getContext().connectAbility(connectPaIntent, conn);
            HiLog.info(LABEL, "连接结果：" + isConnected);
        }
    }

    private void connectAbility(ElementName elementName, IRemoteObject remote, int requestType, MessageParcel data) {
        proxy = new MyRemoteProxy(remote);
        HiLog.error(LABEL, "connectRemoteAbility done");
        if (proxy != null) {
            try {
                proxy.senDataToRemote(requestType, data);
            } catch (RemoteException e) {
                HiLog.error(LABEL, "onAbilityConnectDone RemoteException");
            }
        }
    }


    // FA在请求PA服务时会调用Ability.connectAbility连接PA，连接成功后，需要在onConnect返回一个remote对象，供FA向PA发送消息
    @Override
    protected IRemoteObject onConnect(Intent intent) {
        HiLog.info(LABEL,"onConnect" + (intent != null));
        super.onConnect(intent);
        return remote.asObject();
    }

    class MyRemote extends RemoteObject implements IRemoteBroker {
        private static final int SUCCESS = 0;
        private static final int ERROR = 1;
        private static final int REQUEST_GET_DEVICE = 1;
        private static final int REQUEST_CONNECT_DEVICE = 2;
        private static final int REQUEST_SEND_MSG = 3;
        private static final int REQUEST_SUBSCRIBE = 4;
        private static final int REQUEST_UNSUBSCRIBE = 5;


        public static final int REQUEST_START_ABILITY = 1001;  //启动自己
        private static final int REQUEST_SEND_DATA = 1002;  //接收消息
        private static final int REQUEST_CALL_SUBSCRIBE = 1003;  //接收消息

        private Set<IRemoteObject> remoteObjectHandlers = new HashSet<IRemoteObject>();
        private Thread thread = null;

        MyRemote() {
            super("ServiceRemote");
        }

        @Override
        public IRemoteObject asObject() {
            return this;
        }

        @Override
        public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
            HiLog.info(LABEL,"java接收："+code);
            switch (code) {
                //获取设备
                case REQUEST_GET_DEVICE: {
                    List<DeviceInfo> deviceInfos = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
                    // 返回结果当前仅支持String，对于复杂结构可以序列化为ZSON字符串上报
                    Map<String, Object> result = new HashMap<String, Object>();
                    test();
                    result.put("code", SUCCESS);
                    result.put("deviceInfo", deviceInfos);
                    reply.writeString(ZSONObject.toZSONString(result));
                    break;
                }
                //启动并连接远程FA
                case REQUEST_CONNECT_DEVICE: {
                    String getDeviceId = data.readString();
                    connectRemotePa(getDeviceId, MyRemoteProxy.REQUEST_START_ABILITY, data);
                    break;
                }
                //发送消息
                case REQUEST_SEND_MSG: {
//                    String getData = data.readString();
                    HiLog.info(LABEL, "发送：" + (proxy != null));
//                    HiLog.info(LABEL, "要发送的消息：" + getData);

                    if (isConnected && proxy != null) {
                        try {
                            HiLog.info(LABEL, "senDataToRemote" + MyRemoteProxy.REQUEST_SEND_DATA);
//                            HiLog.info(LABEL, "senDataToRemote" + getData);
                            proxy.senDataToRemote(MyRemoteProxy.REQUEST_SEND_DATA, data);
                        } catch (RemoteException e) {
                            HiLog.info(LABEL, "processEvent RemoteException");
                        }
                    } else {
                        HiLog.info(LABEL, "processEvent RemoteException Error");
                    }
                    break;
                }
                //开启订阅
                case REQUEST_SUBSCRIBE: {
                    Map<String, Object> result = new HashMap<String, Object>();
                    try {
                        isMainStart = true;
                        remoteObjectHandlers.add(data.readRemoteObject());
                        result.put("code", SUCCESS);
                        result.put("msg","订阅成功");
                        result.put("isLocal",isLocal);
                        reply.writeString(ZSONObject.toZSONString(result));
                    }
                    catch (KvStoreException e) {
                        result.put("code", ERROR);
                        result.put("msg","订阅失败");
                        reply.writeString(ZSONObject.toZSONString(result));
                        e.printStackTrace();
                    }

                    break;
                }
                // 取消订阅，置空对端的remoteHandler
                case REQUEST_UNSUBSCRIBE: {
                    Map<String, Object> result = new HashMap<String, Object>();
                    try {
                        // 如果仅支持单FA订阅，可直接置空：remoteObjectHandler = null;
                        remoteObjectHandlers.clear();
                        result.put("code", SUCCESS);
                        result.put("msg","取消订阅成功");
                        reply.writeString(ZSONObject.toZSONString(result));
                    }
                    catch (KvStoreException e) {
                        result.put("code", ERROR);
                        result.put("msg","取消订阅失败");
                        reply.writeString(ZSONObject.toZSONString(result));
                        e.printStackTrace();
                    }
                    break;
                }


                //启动MainAbility
                case REQUEST_START_ABILITY: {
                    String dataStr = data.readString();
                    SendData sendData = new SendData();
                    try {
                        sendData = ZSONObject.stringToClass(dataStr, SendData.class);
                    } catch (RuntimeException e) {
                        HiLog.error(LABEL, "convert failed.");
                    }
                    String getRemoteDeviceId = sendData.getRemoteDeviceId();
                    boolean getIsLocal = data.readBoolean();
                    HiLog.error(LABEL, "param:" + localDeviceId);
                    HiLog.error(LABEL, "param:" + getIsLocal);
                    remoteDeviceId = getRemoteDeviceId;
                    isLocal = getIsLocal;
                    HiLog.error(LABEL, "RemoteServiceAbility::isFirstStart:");
                    Intent secondIntent = new Intent();
                    Operation operation = new Intent.OperationBuilder().withDeviceId("")
                            .withBundleName(getBundleName())
                            .withAbilityName(CommonData.ABILITY_MAIN)
                            .build();
//                    secondIntent.setParam(CommonData.KEY_REMOTE_DEVICEID, localDeviceId);
//                    secondIntent.setParam(CommonData.KEY_IS_LOCAL, isLocal);
                    secondIntent.setOperation(operation);
                    try {
                        List<AbilityInfo> abilityInfoList = getBundleManager().queryAbilityByIntent(secondIntent, 0, 0);
                        if (!isMainStart && abilityInfoList != null && !abilityInfoList.isEmpty()) {
                            startAbility(secondIntent);
                            Map<String, Object> result = new HashMap<String, Object>();
                            result.put("code", SUCCESS);
                            result.put("intent", secondIntent);
                            reply.writeString(ZSONObject.toZSONString(result));
                        }
                    } catch (RemoteException e) {
                        reply.writeString("失败");
                        // 处理异常
                    }
                    initRemoteProxy(data);

                    reply.writeInt(SUCCESS);
                    HiLog.error(LABEL, "成功走过来了");
                    break;
                }
                //接收消息
                case REQUEST_SEND_DATA: {
//                    String dataStr = data.readString();
//                    SendData sendData = new SendData();
//                    try {
//                        sendData = ZSONObject.stringToClass(dataStr, SendData.class);
//                    } catch (RuntimeException e) {
//                        HiLog.error(LABEL, "convert failed.");
//                    }
//                    HiLog.info(LABEL, "接收到数据：" + sendData.getMsg());
                    startNotify(data);
                    break;
                }
                default: {
                    Map<String, Object> result = new HashMap<String, Object>();
                    result.put("abilityError", ERROR);
                    reply.writeString(ZSONObject.toZSONString(result));
                    return false;
                }
            }
            return true;
        }


        //调用js订阅的回调函数
        public void startNotify(MessageParcel data) {
            try {
                reportEvent(data);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        //调用js绑定的方法
        private void reportEvent(MessageParcel data) throws RemoteException {
//            MessageParcel data = MessageParcel.obtain();
            MessageParcel reply = MessageParcel.obtain();
            MessageOption option = new MessageOption();
//            Map<String, Object> event = new HashMap<String, Object>();
//            event.put("abilityEvent", "test event!");
//            data.writeString(ZSONObject.toZSONString(event));
            // 如果仅支持单FA订阅，可直接触发回调：remoteObjectHandler.sendRequest(100, data, reply, option);

            for (IRemoteObject item : remoteObjectHandlers) {
                item.sendRequest(100, data, reply, option);
            }
            reply.reclaim();
            data.reclaim();
        }

    }

    private void test() {
//        route
    }

    class MyRemoteProxy implements IRemoteBroker {
        private static final int SUCCESS = 0;

        private static final int REQUEST_START_ABILITY = 1001;

        private static final int REQUEST_SEND_DATA = 1002;


        private final IRemoteObject remote;

        MyRemoteProxy(IRemoteObject remote) {
            this.remote = remote;
        }

        @Override
        public IRemoteObject asObject() {
            return remote;
        }

        private void senDataToRemote(int requestType, MessageParcel sendData) throws RemoteException {
            MessageParcel data = MessageParcel.obtain();
//            HiLog.info(LABEL, "senDataToRemote要发送的消息：" + sendData.readString());
            MessageParcel reply = MessageParcel.obtain();

            try {
                isLocal = false;
                SendData sendDataR = new SendData();
                sendDataR.setMsg(sendData.readString());
                sendDataR.setRemoteDeviceId(localDeviceId);
                data.writeString(ZSONObject.toZSONString(sendDataR));
                data.writeBoolean(isLocal);
                MessageOption option = new MessageOption(MessageOption.TF_SYNC);
                HiLog.info(LABEL, "sendRequest" + requestType);
                remote.sendRequest(requestType, data, reply, option);
                int ec = reply.readInt();
                if (ec != SUCCESS) {
                    HiLog.error(LABEL, "ec != SUCCESS RemoteException");
                }
            } catch (RemoteException e) {
                HiLog.error(LABEL, "RemoteException");
            } finally {
                data.reclaim();
                reply.reclaim();
            }
        }
    }
}